
#include <scott/SStruct.h>

BOOST_AUTO_TEST_SUITE( SStruct_Test_Suite )

BOOST_AUTO_TEST_CASE( SStructTypeDescriptor_SimpleType_Test )
{
	//SStructTypeDescriptorSp std = 
	//	SStructTypeDescriptor::Create("plugin", "SimpleStruct", "Una semplice struttura");
	//std->AddMember("b", "Un byte", STypeByte);		
	//std->AddMember("num", "Un numbero", STypeNumber);
	//std->AddMember("c", "Un carattere", STypeChar);
	//std->AddMember("str", "Una stringa", STypeString);

	//SStructSp s = SStruct::Create(std);
	//s->Set("b", SByte::Create(10) );
	//s->Set("num", SNumber::Create(1000) );
	//s->Set("c", SChar::Create('C') );
	//s->Set("str", SString::Create("Hello") );

	//SByteSp b = s->Get<SByte>("b");
	//SNumberSp num = s->Get<SNumber>("num");
	//SCharSp c = s->Get<SChar>("c");
	//SStringSp str = s->Get<SString>("str");


	SStructTypeDescriptorSp std = SStructTypeDescriptor::Create("plugin", "SimpleStruct", "A SimpleStruct");

	BOOST_CHECK( std->GetName() == "SimpleStruct" );
	BOOST_CHECK( std->GetDescription() == "A SimpleStruct" );
	BOOST_CHECK( std->GetNumberOfMembers() == 0 );
	BOOST_CHECK( std->IsValid() == true );
	BOOST_CHECK( std->Describe(STypeStruct) == true );		
	BOOST_CHECK( std->GetDescribedType() == STypeStruct );		

	std->AddMember("Str", "A string", STypeString);
	std->AddMember("Num", "A number", STypeNumber);
	std->AddMember("C", "A char", STypeChar);
	std->AddMember("B", "A byte", STypeByte);

	BOOST_CHECK( std->IsValid() == true );
	BOOST_CHECK( std->GetNumberOfMembers() == 4 );

    BOOST_CHECK( std->IsDefined("Str") == true );
    BOOST_CHECK( std->IsDefined("N") == false );

	BOOST_CHECK( std->GetMember("Str")->GetType() == STypeString );
	BOOST_CHECK( std->GetMember("Num")->GetType() == STypeNumber );
	BOOST_CHECK( std->GetMember("C")->GetType() == STypeChar );
	BOOST_CHECK( std->GetMember("B")->GetType() == STypeByte );
}

BOOST_AUTO_TEST_CASE( SetGet_SimpleStruct_Test )
{
	// Data
	SStructTypeDescriptorSp std = SStructTypeDescriptor::Create("plugin", "SimpleStruct", "A SimpleStruct");
	std->AddMember("Str", "A string", STypeString);
	std->AddMember("Num", "A number", STypeNumber);
	std->AddMember("C", "A char", STypeChar);
	std->AddMember("B", "A byte", STypeByte);	

	// Test
	SStructSp s = SStruct::Create(std);

	BOOST_CHECK( s->IsSet("Str") == false );
	BOOST_CHECK( s->IsSet("Num") == false );
	BOOST_CHECK( s->IsSet("C") == false );
	BOOST_CHECK( s->IsSet("B") == false );
	BOOST_CHECK_THROW(  s->IsSet("N"), SArgumentException ); 

	s->Set("Str", SString::Create("Hello") );
	s->Set("Num", SNumber::Create(10) );
	s->Set("C", SChar::Create('C') );
	s->Set("B", SByte::Create(10) );
	BOOST_CHECK_THROW( s->Set("Str", SNumber::Create(10)), SArgumentException ); 
	BOOST_CHECK_THROW( s->Set("N", SNumber::Create(10)), SArgumentException );   

	BOOST_CHECK( s->IsSet("Str") == true );
	BOOST_CHECK( s->IsSet("Num") == true );
	BOOST_CHECK( s->IsSet("C") == true );
	BOOST_CHECK( s->IsSet("B") == true );
	BOOST_CHECK_THROW(  s->IsSet("N"), SArgumentException ); 

  	BOOST_CHECK( s->Get<SString>("Str")->Get() == "Hello" );
  	BOOST_CHECK( s->Get<SNumber>("Num")->Get() == 10 );
  	BOOST_CHECK( s->Get<SChar>("C")->Get() == 'C' );
  	BOOST_CHECK( s->Get<SByte>("B")->Get() == 10 );
		
	// Set with index
	SStructSp s2 = SStruct::Create(std);
	s2->Set(0, SString::Create("Hello") );
	s2->Set(1, SNumber::Create(10) );
	s2->Set(2, SChar::Create('C') );
	s2->Set(3, SByte::Create(10) );
	BOOST_CHECK_THROW( s2->Set(4, SNumber::Create(10)), SArgumentException ); 
	
  	BOOST_CHECK( s2->Get<SString>(0)->Get() == "Hello" );
  	BOOST_CHECK( s2->Get<SNumber>(1)->Get() == 10 );
  	BOOST_CHECK( s2->Get<SChar>(2)->Get() == 'C' );
  	BOOST_CHECK( s2->Get<SByte>(3)->Get() == 10 );
}

BOOST_AUTO_TEST_CASE( ToString_Test )
{
	// Data
	SStructTypeDescriptorSp std = SStructTypeDescriptor::Create("plugin", "SimpleStruct", "A SimpleStruct");
	std->AddMember("Str", "A string", STypeString);
	std->AddMember("Num", "A number", STypeNumber);
	std->AddMember("C", "A char", STypeChar);
	std->AddMember("B", "A byte", STypeByte);	

	SStructSp s = SStruct::Create(std);

	BOOST_CHECK( s->ToString() == "{  }" );		                              

	s->Set("Str", SString::Create("Hello") );

	BOOST_CHECK( s->ToString() == "{ Str = \"Hello\" }" );		                              

	s->Set("C", SChar::Create('C') );

	BOOST_CHECK( s->ToString() == "{ Str = \"Hello\", C = 'C' }" );		                              

	s->Set("Num", SNumber::Create(10) );
	s->Set("B", SByte::Create(10) );

	// Test
	BOOST_CHECK( s->ToString() == "{ Str = \"Hello\", Num = 10, C = 'C', B = 10 }" );		                              

}

BOOST_AUTO_TEST_CASE( SStruct_Parse_Test )
{
	// Data
	SStructTypeDescriptorSp std = SStructTypeDescriptor::Create("plugin", "SimpleStruct", "A SimpleStruct");
	std->AddMember("Str", "A string", STypeString);
	std->AddMember("Num", "A number", STypeNumber);
	std->AddMember("C", "A char", STypeChar);
	std->AddMember("B", "A byte", STypeByte);	

	// Test                                             
	string s = "{ Str = \"Hello\", Num = 10, C = 'A', B = 253 }";
	string s2 = "{ Str = \"Hello\", Num = 10, C = 'A' }";
	string s3 = "{ Str = \"Hello\" }";

	BOOST_CHECK( SStruct::Parse(std, " { Str = \"Hello\", Num = 10, C = 'A', B = 0xFD } ")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ \"Hello\", Num = 10, C = 'A', B = 253}")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ \"Hello\", 10, C = 'A', B = 0xFD }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ \"Hello\", 10, 'A', B = 0xFD }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ \"Hello\", 10, 'A', 0xFD }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ \"Hello\", 10, 'A' }")->ToString() == s2 );
	BOOST_CHECK( SStruct::Parse(std, "{ Num = 10, C = 'A', Str = \"Hello\", B = 0xFD }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ C = 'A', Num = 10, Str = \"Hello\", B = 0xFD }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ \"Hello\", 10, B = 0xFD, C = 'A' }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ \"Hello\" }")->ToString() == s3 );
	BOOST_CHECK( SStruct::Parse(std, "{}")->ToString() == "{  }" );
	BOOST_CHECK( SStruct::Parse(std, "{    }")->ToString() == "{  }" );

	BOOST_CHECK_THROW( SStruct::Parse(std, ""), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "{ \"Hello\", 10, 'A'")->ToString(), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "{ 10, \"Hello\", 'A', 0xFD }"), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "10"), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "0x23"), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "'A'"), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "\"Hello\""), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "red"), SParseException );
}

BOOST_AUTO_TEST_CASE( Parse2_Test )
{
	// Data
	SStructTypeDescriptorSp std1 = SStructTypeDescriptor::Create("plugin", "SimpleStruct", "A SimpleStruct");
	std1->AddMember("str", "A string", STypeString);
	std1->AddMember("num", "A number", STypeNumber);

	SEnumTypeDescriptorSp etd = SEnumTypeDescriptor::Create("plugin", "colors", "");
	etd->AddEntry("red", 0, "red color");			
	etd->AddEntry("yellow", 1, "yellow color");
	etd->AddEntry("green", 2, "green color");

	SStructTypeDescriptorSp std = SStructTypeDescriptor::Create("plugin", "SimpleStruct", "A SimpleStruct");
	std->AddMember("num", "A number", STypeNumber);
	std->AddMember("color", "A color", etd);
	std->AddMember("ss", "A simple struct", std1);	

	// Test                                             
	string s = "{ num = 10, color = red, ss = { str = \"Hi\", num = 65535 } }";

	BOOST_CHECK( SStruct::Parse(std, "{ num=10, color=red, ss={str=\"Hi\", num=0xFFFF}  }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ 10, color=red, ss={str=\"Hi\", num=0xFFFF}  }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ 10, red, ss={str=\"Hi\", num=0xFFFF}  }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ 10, red, {str=\"Hi\", num=0xFFFF}  }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ 10, red, { \"Hi\", 0xFFFF}  }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ 10, red, { num=0xFFFF, str=\"Hi\"}  }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ ss={str=\"Hi\", num=0xFFFF}, num=10, color=red  }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ color=red, ss={str=\"Hi\", num=0xFFFF}, num=0x00A  }")->ToString() == s );

	BOOST_CHECK_THROW( SStruct::Parse(std, "{ num=10, color=red, ss=str=\"Hi\", num=0xFFFF}  }"), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "{ num=10, color=red, ss={str=\"Hi\", num=0xFFFF  }"), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "{ num=10, color=red, ss={str=, num=0xFFFF}  }"), SParseException );
}

BOOST_AUTO_TEST_CASE( Parse3_Test )
{
	// Data
	SStructTypeDescriptorSp std1 = SStructTypeDescriptor::Create("plugin", "SimpleStruct", "A SimpleStruct");
	std1->AddMember("s", "A string", STypeString);
	std1->AddMember("n", "A number", STypeNumber);

	SStructTypeDescriptorSp std2 = SStructTypeDescriptor::Create("plugin", "SimpleStruct", "A SimpleStruct");
	std2->AddMember("b", "", STypeByte);
	std2->AddMember("s1", "", std1);
	std2->AddMember("s2", "", std1);

	SStructTypeDescriptorSp std = SStructTypeDescriptor::Create("plugin", "SimpleStruct", "A SimpleStruct");
	std->AddMember("n1", "", STypeNumber);
	std->AddMember("s1", "", std1);
	std->AddMember("s2", "", std2);
	std->AddMember("n2", "", STypeNumber);

	// Test                                             
	string s = "{ n1 = 10, s1 = { s = \"Hi\", n = 1 }, s2 = { b = 0, s1 = { s = \"Hi\", n = 1 }, s2 = { s = \"Hi\", n = 2 } }, n2 = 20 }";

	BOOST_CHECK( SStruct::Parse(std, "{ n1 = 10, s1 = { s = \"Hi\", n = 1 }, s2 = { b = 0, s1 = { s = \"Hi\", n = 1 }, s2 = { s = \"Hi\", n = 2 } }, n2 = 20 }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ n1 = 10, s2 = { b = 0, s1 = { s = \"Hi\", n = 1 }, s2 = { s = \"Hi\", n = 2 } }, s1 = { s = \"Hi\", n = 1 }, n2 = 20 }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ s2 = { b = 0, s1 = { s = \"Hi\", n = 1 }, s2 = { s = \"Hi\", n = 2 } }, s1 = { s = \"Hi\", n = 1 }, n2 = 20, n1 = 10 }")->ToString() == s );
	BOOST_CHECK( SStruct::Parse(std, "{ 10, {\"Hi\", 1}, {  0, {\"Hi\", 1}, {\"Hi\", 2}  }, 20 }")->ToString() == s );

	BOOST_CHECK_THROW( SStruct::Parse(std, "{ 10, {\"Hi\", 1}, {  0, \"Hi\", 1}, {\"Hi\", 2}  }, 20 }"), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "{ 10, {\"Hi\", 1}, {  0, {\"Hi\", 1}, {\"Hi\" 2}  }, 20 }"), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "{ 10, {\"Hi\", 1}, {  0, {\"Hi\", 1}, {\"Hi\", 2  }, 20 }"), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "{ 10, {\"Hi\", 1, {  0, {\"Hi\", 1}, {\"Hi\", 2}  }, 20 }"), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "{ 10, {\"Hi\", 1} {  0, {\"Hi\", 1}, {\"Hi\", 2}  }, 20 }"), SParseException );
	BOOST_CHECK_THROW( SStruct::Parse(std, "{ 10, {\"Hi\", 1}, {  0, \"Hi\", 1, {\"Hi\", 2}  }, 20 }"), SParseException );
}


BOOST_AUTO_TEST_SUITE_END()
